// Copyright Epic Games, Inc. All Rights Reserved. // 版权声明，Epic Games 公司保留所有权利

#include "LyraGlobalAbilitySystem.h" // 包含对应的头文件

#include "AbilitySystem/LyraAbilitySystemComponent.h" // 包含 Lyra 能力系统组件的头文件

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraGlobalAbilitySystem) // 包含由 UHT 生成的内联函数文件

/**
 * 将指定的能力添加到指定的 Ability System Component (ASC)
 * @param Ability 要添加的能力类
 * @param ASC 目标能力系统组件
 */
void FGlobalAppliedAbilityList::AddToASC(TSubclassOf<UGameplayAbility> Ability, ULyraAbilitySystemComponent* ASC)
{
	if (FGameplayAbilitySpecHandle* SpecHandle = Handles.Find(ASC)) // 检查 ASC 是否已存在于此列表中
	{
		RemoveFromASC(ASC); // 如果存在，先移除旧的能力
	}

	UGameplayAbility* AbilityCDO = Ability->GetDefaultObject<UGameplayAbility>(); // 获取能力的类默认对象 (CDO)
	FGameplayAbilitySpec AbilitySpec(AbilityCDO); // 创建能力规格，使用 CDO
	const FGameplayAbilitySpecHandle AbilitySpecHandle = ASC->GiveAbility(AbilitySpec); // 将能力授予 ASC，并获取能力规格句柄
	Handles.Add(ASC, AbilitySpecHandle); // 将 ASC 和句柄的对应关系添加到映射表中
}

/**
 * 从指定的 ASC 移除能力
 * @param ASC 目标能力系统组件
 */
void FGlobalAppliedAbilityList::RemoveFromASC(ULyraAbilitySystemComponent* ASC)
{
	if (FGameplayAbilitySpecHandle* SpecHandle = Handles.Find(ASC)) // 检查 ASC 是否存在于映射表中
	{
		ASC->ClearAbility(*SpecHandle); // 从 ASC 清除该能力
		Handles.Remove(ASC); // 从映射表中移除该 ASC 的条目
	}
}

/**
 * 从所有 ASC 移除能力
 */
void FGlobalAppliedAbilityList::RemoveFromAll()
{
	for (auto& KVP : Handles) // 遍历映射表中的所有键值对
	{
		if (KVP.Key != nullptr) // 检查 ASC 指针是否有效
		{
			KVP.Key->ClearAbility(KVP.Value); // 从该 ASC 清除能力
		}
	}
	Handles.Empty(); // 清空映射表
}

/**
 * 将指定的效果添加到指定的 Ability System Component (ASC)
 * @param Effect 要添加的效果类
 * @param ASC 目标能力系统组件
 */
void FGlobalAppliedEffectList::AddToASC(TSubclassOf<UGameplayEffect> Effect, ULyraAbilitySystemComponent* ASC)
{
	if (FActiveGameplayEffectHandle* EffectHandle = Handles.Find(ASC)) // 检查 ASC 是否已存在于此列表中
	{
		RemoveFromASC(ASC); // 如果存在，先移除旧的效果
	}

	const UGameplayEffect* GameplayEffectCDO = Effect->GetDefaultObject<UGameplayEffect>(); // 获取效果的类默认对象 (CDO)
	const FActiveGameplayEffectHandle GameplayEffectHandle = ASC->ApplyGameplayEffectToSelf(GameplayEffectCDO, /*Level=*/ 1, ASC->MakeEffectContext()); // 将效果应用到 ASC 自身，并获取效果句柄
	Handles.Add(ASC, GameplayEffectHandle); // 将 ASC 和句柄的对应关系添加到映射表中
}

/**
 * 从指定的 ASC 移除效果
 * @param ASC 目标能力系统组件
 */
void FGlobalAppliedEffectList::RemoveFromASC(ULyraAbilitySystemComponent* ASC)
{
	if (FActiveGameplayEffectHandle* EffectHandle = Handles.Find(ASC)) // 检查 ASC 是否存在于映射表中
	{
		ASC->RemoveActiveGameplayEffect(*EffectHandle); // 从 ASC 移除该主动游戏效果
		Handles.Remove(ASC); // 从映射表中移除该 ASC 的条目
	}
}

/**
 * 从所有 ASC 移除效果
 */
void FGlobalAppliedEffectList::RemoveFromAll()
{
	for (auto& KVP : Handles) // 遍历映射表中的所有键值对
	{
		if (KVP.Key != nullptr) // 检查 ASC 指针是否有效
		{
			KVP.Key->RemoveActiveGameplayEffect(KVP.Value); // 从该 ASC 移除主动游戏效果
		}
	}
	Handles.Empty(); // 清空映射表
}

ULyraGlobalAbilitySystem::ULyraGlobalAbilitySystem() // 构造函数定义
{
}

/**
 * 将能力应用于所有已注册的 ASC
 * @param Ability 要应用的能力类
 */
void ULyraGlobalAbilitySystem::ApplyAbilityToAll(TSubclassOf<UGameplayAbility> Ability)
{
	if ((Ability.Get() != nullptr) && (!AppliedAbilities.Contains(Ability))) // 检查能力类有效且尚未应用
	{
		FGlobalAppliedAbilityList& Entry = AppliedAbilities.Add(Ability); // 在 AppliedAbilities 映射表中添加新条目，键为 Ability，值为新的 FGlobalAppliedAbilityList
		for (ULyraAbilitySystemComponent* ASC : RegisteredASCs) // 遍历所有已注册的 ASC
		{
			Entry.AddToASC(Ability, ASC); // 将能力添加到当前 ASC
		}
	}
}

/**
 * 将效果应用于所有已注册的 ASC
 * @param Effect 要应用的效果类
 */
void ULyraGlobalAbilitySystem::ApplyEffectToAll(TSubclassOf<UGameplayEffect> Effect)
{
	if ((Effect.Get() != nullptr) && (!AppliedEffects.Contains(Effect))) // 检查效果类有效且尚未应用
	{
		FGlobalAppliedEffectList& Entry = AppliedEffects.Add(Effect); // 在 AppliedEffects 映射表中添加新条目，键为 Effect，值为新的 FGlobalAppliedEffectList
		for (ULyraAbilitySystemComponent* ASC : RegisteredASCs) // 遍历所有已注册的 ASC
		{
			Entry.AddToASC(Effect, ASC); // 将效果添加到当前 ASC
		}
	}
}

/**
 * 从所有已注册的 ASC 移除能力
 * @param Ability 要移除的能力类
 */
void ULyraGlobalAbilitySystem::RemoveAbilityFromAll(TSubclassOf<UGameplayAbility> Ability)
{
	if ((Ability.Get() != nullptr) && AppliedAbilities.Contains(Ability)) // 检查能力类有效且已应用
	{
		FGlobalAppliedAbilityList& Entry = AppliedAbilities[Ability]; // 获取对应的全局已应用能力列表引用
		Entry.RemoveFromAll(); // 从所有 ASC 移除该能力
		AppliedAbilities.Remove(Ability); // 从 AppliedAbilities 映射表中移除该能力条目
	}
}

/**
 * 从所有已注册的 ASC 移除效果
 * @param Effect 要移除的效果类
 */
void ULyraGlobalAbilitySystem::RemoveEffectFromAll(TSubclassOf<UGameplayEffect> Effect)
{
	if ((Effect.Get() != nullptr) && AppliedEffects.Contains(Effect)) // 检查效果类有效且已应用
	{
		FGlobalAppliedEffectList& Entry = AppliedEffects[Effect]; // 获取对应的全局已应用效果列表引用
		Entry.RemoveFromAll(); // 从所有 ASC 移除该效果
		AppliedEffects.Remove(Effect); // 从 AppliedEffects 映射表中移除该效果条目
	}
}

/**
 * 注册一个 ASC 到全局系统，并应用所有已激活的全局效果/能力
 * @param ASC 要注册的能力系统组件
 */
void ULyraGlobalAbilitySystem::RegisterASC(ULyraAbilitySystemComponent* ASC)
{
	check(ASC); // 断言 ASC 不为空

	for (auto& Entry : AppliedAbilities) // 遍历所有已应用的全局能力
	{
		Entry.Value.AddToASC(Entry.Key, ASC); // 将当前能力添加到新注册的 ASC
	}
	for (auto& Entry : AppliedEffects) // 遍历所有已应用的全局效果
	{
		Entry.Value.AddToASC(Entry.Key, ASC); // 将当前效果添加到新注册的 ASC
	}

	RegisteredASCs.AddUnique(ASC); // 将 ASC 添加到已注册数组（确保不重复）
}

/**
 * 从全局系统注销一个 ASC，并移除所有已激活的全局效果/能力
 * @param ASC 要注销的能力系统组件
 */
void ULyraGlobalAbilitySystem::UnregisterASC(ULyraAbilitySystemComponent* ASC)
{
	check(ASC); // 断言 ASC 不为空
	for (auto& Entry : AppliedAbilities) // 遍历所有已应用的全局能力
	{
		Entry.Value.RemoveFromASC(ASC); // 从要注销的 ASC 移除当前能力
	}
	for (auto& Entry : AppliedEffects) // 遍历所有已应用的全局效果
	{
		Entry.Value.RemoveFromASC(ASC); // 从要注销的 ASC 移除当前效果
	}

	RegisteredASCs.Remove(ASC); // 从已注册数组中移除该 ASC
}